package sample;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.List;

import gnu.io.CommPort;
import gnu.io.CommPortIdentifier;
import gnu.io.NoSuchPortException;
import gnu.io.PortInUseException;
import gnu.io.SerialPort;
import gnu.io.SerialPortEvent;
import gnu.io.SerialPortEventListener;
import gnu.io.UnsupportedCommOperationException;
import javafx.application.Platform;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.scene.control.Button;
import javafx.scene.control.ComboBox;
import javafx.scene.control.TextArea;
import javafx.scene.control.TextField;
import javafx.scene.input.MouseEvent;
import javafx.stage.DirectoryChooser;

public class Controller {
    @FXML
    TextArea action_info;
    @FXML
    TextField tf_pic_version;
    @FXML
    TextField tf_device_node;
    @FXML
    TextField tf_port_baudrate;
    @FXML
    TextField tf_pic_id_a, tf_pic_id_b;//AB面显示图片id
    @FXML
    TextField tf_ab_display_text_a, tf_ab_display_text_b;//AB面第一行内容
    @FXML
    TextField tf_ab_display_text2_a, tf_ab_display_text2_b;//AB面第二行内容
    @FXML
    ComboBox cb_display_color_a, cb_display_color_b;//AB面显示内容颜色
    @FXML
    ComboBox cb_alignment_style_a, cb_alignment_style_b;//AB面显示内容对齐方式
    @FXML
    ComboBox cb_response_style;//主动上报数据类型
    @FXML
    ComboBox cb_serial_list;//端口列表
    @FXML
    ComboBox cb_pic_color;//图库颜色
    @FXML
    TextField tf_card_num;
    @FXML
    Button btn_send_card_num;
    @FXML
    Button btn_select_directory;
    @FXML
    TextField tf_delay_input;
    @FXML
    TextField tf_pic_senddelay;

    private static final byte UPLOAD_ACTIVE = 0;
    private static final byte UPLOAD_RESPONSE = 1;
    private SerialPort mSerialPort;
    private String updatePicPath;

    public void init() {
        initView();
    }

    private void initView() {
        cb_alignment_style_a.getSelectionModel().select(0);
        cb_alignment_style_b.getSelectionModel().select(0);
        cb_display_color_a.getSelectionModel().select(0);
        cb_display_color_b.getSelectionModel().select(0);
        cb_response_style.getSelectionModel().select(0);
        cb_pic_color.getSelectionModel().select(0);
        tf_pic_id_a.textProperty().addListener(new ChangeListener<String>() {
            @Override
            public void changed(ObservableValue<? extends String> observable, String oldValue,
                                String newValue) {
                if (!newValue.matches("^[0-9]{0,3}$") || (newValue.length() > 0 && Integer.parseInt(newValue) > 255)) {
                    tf_pic_id_a.setText(oldValue);
                }
            }
        });
        tf_pic_version.textProperty().addListener(new ChangeListener<String>() {
            @Override
            public void changed(ObservableValue<? extends String> observable, String oldValue,
                                String newValue) {
                if (!newValue.matches("^[0-9]{0,3}$") || (newValue.length() > 0 && Integer.parseInt(newValue) > 255)) {
                    tf_pic_version.setText(oldValue);
                }
            }
        });
        tf_device_node.textProperty().addListener(new ChangeListener<String>() {
            @Override
            public void changed(ObservableValue<? extends String> observable, String oldValue,
                                String newValue) {
                if (!newValue.matches("[0-9]+")) {
                    tf_device_node.setText(oldValue);
                }
            }
        });
        tf_pic_senddelay.textProperty().addListener(new ChangeListener<String>() {
            @Override
            public void changed(ObservableValue<? extends String> observable, String oldValue,
                                String newValue) {
                if (!newValue.matches("[0-9]+")) {
                    tf_pic_senddelay.setText(oldValue);
                }
            }
        });
    }

    @FXML
    public void onFindPortListener(MouseEvent mouseEvent) {
        ArrayList<String> portNames = findSerialPort();
        if (null != portNames && portNames.size() > 0) {
            ObservableList<String> serialPortItems =
                    FXCollections.observableArrayList();
            for (String portName : portNames) {
                serialPortItems.add(portName);
            }
            cb_serial_list.setItems(serialPortItems);
            cb_serial_list.getSelectionModel().select(0);
        } else {
            addStrText("没有找到可用端口");
        }
    }

    @FXML
    public void onOpenPortListener(MouseEvent mouseEvent) {
        if (null != mSerialPort) {
            closePort();
        }
        String serialPortName = (String) cb_serial_list.getSelectionModel().getSelectedItem();
        String baudrate = tf_port_baudrate.getText();
        if (!baudrate.matches("[0-9]+")) {
            addStrText("波特率错误");
            return;
        }
        mSerialPort = openPort(serialPortName, Integer.parseInt(baudrate));
        if (null != mSerialPort) {
            addPortEventListener();
        }
    }


    //点击按钮主动上报数据
    @FXML
    public void onSendSerialData(MouseEvent actionEvent) {
        if (null == mSerialPort) {
            addStrText("串口已经关闭");
            return;
        }
        switch (cb_response_style.getSelectionModel().getSelectedIndex()) {
            case 0:
                packageClockSynData(Constant.CLOCK_SYNCHRONIZATION, getDeviceId(), UPLOAD_ACTIVE);
                break;
            case 1:
                packageDisplayData(Constant.DISPLAY_A, getDeviceId(), UPLOAD_ACTIVE);
                break;
            case 2:
                packageDisplayData(Constant.DISPLAY_B, getDeviceId(), UPLOAD_ACTIVE);
                break;
            default:
                break;
        }
    }

    @FXML
    public void onSendCardNum(MouseEvent mouseEvent) {
        try {
            if (!tf_card_num.getText().matches("^[0-9]+$")) {
                addStrText("请输入正确的卡数量");
                return;
            }
            List<Byte> params = new ArrayList<Byte>();
            int cardNum = Integer.parseInt(tf_card_num.getText());
            params.add((byte) cardNum);
            responseData(Constant.WHAT_SEND_CARD_NUM, params, getDeviceId(), UPLOAD_ACTIVE);
        } catch (Exception e) {
            addStrText("Exception:" + e.getMessage());
        }
    }

    @FXML
    public void onSelectPicPath(MouseEvent mouseEvent) {
        DirectoryChooser directoryChooser = new DirectoryChooser();
        directoryChooser.setTitle("选择图片路径");
        File directory = directoryChooser.showDialog(btn_select_directory.getScene().getWindow());
        if (null == directory) {
            return;
        }
        updatePicPath = directory.getAbsolutePath();
    }

    @FXML
    private void onSendUpdatePics(MouseEvent mouseEvent) {
        sendPicData(getDeviceId(), UPLOAD_ACTIVE);
    }

    @FXML
    public void onClosePortListener(MouseEvent mouseEvent) {
        closePort();
    }

    private byte[] getDeviceId() {
        byte[] deviceId = new byte[2];
        deviceId[0] = (byte) (Integer.parseInt(tf_device_node.getText()) >> 8 & 0xff);
        deviceId[1] = (byte) (Integer.parseInt(tf_device_node.getText()) & 0xff);
        return deviceId;
    }

    private List<File> files;

    private void sendPicData(byte[] deviceId, byte uploadStyle) {
        try {
            if (null == updatePicPath || 0 == updatePicPath.length()) {
                addStrText("必须先选择图片库路径");
                return;
            }
            final byte[] tempDeviceId = deviceId;
            final byte tempUploadStyle = uploadStyle;
            File directory = new File(updatePicPath);
            if (directory.isDirectory()) {
                files = new ArrayList<File>(Arrays.asList(directory.listFiles()));
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        Iterator<File> iterator = files.iterator();
                        while (iterator.hasNext()) {
                            try {
                                Thread.sleep(Integer.parseInt(tf_pic_senddelay.getText()));
                            } catch (Exception e) {

                            }
                            packageUpdateData(Constant.UPDATE_PICTURE, iterator.next(),
                                    tempDeviceId,
                                    tempUploadStyle);
                            iterator.remove();
                        }
                        addStrText(tf_device_node.getText() + "号卡图片发送完成");
                    }
                }).start();
            }
        } catch (Exception e) {
            addStrText("Exception:" + e.getMessage());
        }
    }

    /*
    字节（高在前） 备注
    1             起始位0x02
    2             总包长度，含起始位和结束位
    2             命令数据为目的设备节点，应答数据为本设备节点
    1             命令字
    N             参数
    1             除了起始位和结束位的数据和校验
    1             结束位0x03
     */
    private void packageClockSynData(byte cmd, byte[] deviceId, byte uploadStyle) {
        List<Byte> paramList = new ArrayList<Byte>();
        //响应吗 1字节
        paramList.add(Constant.SUCCESS_OPERATION);
        responseData(cmd, paramList, deviceId, uploadStyle);
    }

    /**
     * 显示数据
     *
     * @param cmd
     */
    private void packageDisplayData(byte cmd, byte[] deviceId, byte uploadStyle) {
        try {
            //组装参数
            List<Byte> paramList = new ArrayList<Byte>();
            //图片id 2字节
            int lines = 0;
            String str, str2;
            paramList.add((byte) 0);
            if (Constant.DISPLAY_A == cmd) {
                paramList.add((byte) Integer.parseInt(tf_pic_id_a.getText()));
                //文字区对其方式 1字节
                paramList.add((byte) cb_alignment_style_a.getSelectionModel().getSelectedIndex());
                //文字内容 N字节 每个字符（颜色 1字节，汉子unicode编码（取最后两个字节） 英文ASCII编码 2字节 多余字节省略）
                str = tf_ab_display_text_a.getText();
                if (str.length() > 0) {
                    lines++;
                }
                //第二行文字内容
                str2 = tf_ab_display_text2_a.getText();
                if (str2.length() > 0) {
                    lines++;
                }
            } else {
                paramList.add((byte) Integer.parseInt(tf_pic_id_b.getText()));
                paramList.add((byte) cb_alignment_style_b.getSelectionModel().getSelectedIndex());
                //文字内容 N字节 每个字符（颜色 1字节，汉子unicode编码（取最后两个字节） 英文ASCII编码 2字节 多余字节省略）
                str = tf_ab_display_text_b.getText();
                if (str.length() > 0) {
                    lines++;
                }
                //第二行文字内容
                str2 = tf_ab_display_text2_b.getText();
                if (str2.length() > 0) {
                    lines++;
                }
            }
            byte charColor = 0;
            if (Constant.DISPLAY_A == cmd) {
                charColor = (byte) cb_display_color_a.getSelectionModel().getSelectedIndex();
            } else {
                charColor = (byte) cb_display_color_b.getSelectionModel().getSelectedIndex();
            }
            //行数 1字节
            paramList.add((byte) lines);

            for (int x = 0; x < str.length(); x++) {
                //指定字符颜色
                paramList.add(charColor);

                String singleChar = str.substring(x, x + 1);
                if (singleChar.getBytes().length == 1) {
                    paramList.add((byte) 0x00);
                    paramList.add(singleChar.getBytes("ASCII")[0]);
                } else {
                    byte[] bytes = singleChar.getBytes("unicode");
                    paramList.add(bytes[bytes.length - 2]);
                    paramList.add(bytes[bytes.length - 1]);
                }
            }
            //两行内容之间的换行符
            paramList.add((byte) 0x10);

            //获取第二行内容字节数组
            for (int x = 0; x < str2.length(); x++) {
                //指定字符颜色
                paramList.add(charColor);

                String singleChar = str2.substring(x, x + 1);
                if (singleChar.getBytes().length == 1) {
                    paramList.add((byte) 0x00);
                    paramList.add(singleChar.getBytes("ASCII")[0]);
                } else {
                    byte[] bytes = singleChar.getBytes("unicode");
                    paramList.add(bytes[bytes.length - 2]);
                    paramList.add(bytes[bytes.length - 1]);
                }
            }
            responseData(cmd, paramList, deviceId, uploadStyle);
        } catch (Exception e) {
            addStrText("Exception:" + e.getMessage());
        }

    }

    private byte[] picColors = new byte[]{0x00, 0x01, 0x02};

    /**
     * 图片库更新
     *
     * @param cmd
     */
    private void packageUpdateData(byte cmd, File pic, byte[] deviceId, byte uploadStyle) {
        String fileName = "";
        try {
            List<Byte> paramList = new ArrayList<Byte>();
            //需要更新的图片数量 1字节
            paramList.add((byte) files.size());
            //新增图片库版本号 2字节
            paramList.add((byte) 0);
            paramList.add((byte) Integer.parseInt(tf_pic_version.getText()));
            //图片id 2字节
            paramList.add((byte) 0);


            fileName = pic.getAbsolutePath();
            String name = fileName.substring(fileName.lastIndexOf(File.separator) + 1,
                    fileName.lastIndexOf("."));
            int index = Integer.parseInt(name, 16);
            paramList.add((byte) index);
            //图片颜色信息 1字节
            byte color;
            switch (index) {
                case 1:
                    color = picColors[2];
                    break;
                case 2:
                    color = picColors[0];
                    break;
                case 3:
                    color = picColors[1];
                    break;
                case 4:
                    color = picColors[1];
                    break;
                case 5:
                    color = picColors[1];
                    break;
                case 6:
                    color = picColors[1];
                    break;
                case 7:
                    color = picColors[2];
                    break;
                case 9:
                    color = picColors[0];
                    break;
                case 10:
                    color = picColors[1];
                    break;
                case 11:
                    color = picColors[1];
                    break;
                case 12:
                    color = picColors[2];
                    break;
                case 13:
                    color = picColors[2];
                    break;
                case 15:
                    color = picColors[0];
                    break;
                default:
                    color = picColors[0];
                    break;

            }
            paramList.add(color);
            //图片位数据 N字节
            byte[] fileHex = readFileByte(pic);
            for (byte b : fileHex) {
                paramList.add(b);
            }
            responseData(cmd, paramList, deviceId, uploadStyle);
        } catch (StringIndexOutOfBoundsException e) {
            System.out.println(fileName + "    不是图片");
        } catch (NumberFormatException e) {
            System.out.println(fileName + "    文件名称错误");
        } catch (Exception e) {
            addStrText("Exception:" + e.getMessage());
        }

    }

    /**
     * 组装数据包
     *
     * @param cmd      命令字
     * @param params   数据域
     * @param deviceId 设备节点
     */
    private void responseData(byte cmd, List<Byte> params, byte[] deviceId, byte uploadStyle) {
        try {
            int offset = 0;
            byte[] tempData = new byte[(params.size() + 6) * 2 + 2];
            //协议开始位
            tempData[offset++] = Constant.DATA_START;
            //总包长度
            byte lengthHigh = (byte) ((params.size() + 8) >> 8 & 0xff);
            byte lengthLower = (byte) ((params.size() + 8) & 0xff);
            if (lengthHigh == Constant.DATA_START || lengthHigh == Constant.DATA_END || lengthHigh == Constant.DATA_TRANSFER_FLAG) {
                tempData[offset++] = Constant.DATA_TRANSFER_FLAG;
            }
            tempData[offset++] = lengthHigh;
            if (lengthLower == Constant.DATA_START || lengthLower == Constant.DATA_END || lengthLower == Constant.DATA_TRANSFER_FLAG) {
                tempData[offset++] = Constant.DATA_TRANSFER_FLAG;
            }
            tempData[offset++] = lengthLower;
            //设备节点
            byte deviceHigh = deviceId[0];
            byte deviceLower = deviceId[1];
            if (deviceHigh == Constant.DATA_START || deviceHigh == Constant.DATA_END || deviceHigh == Constant.DATA_TRANSFER_FLAG) {
                tempData[offset++] = Constant.DATA_TRANSFER_FLAG;
            }
            tempData[offset++] = deviceHigh;
            if (deviceLower == Constant.DATA_START || deviceLower == Constant.DATA_END || deviceLower == Constant.DATA_TRANSFER_FLAG) {
                tempData[offset++] = Constant.DATA_TRANSFER_FLAG;
            }
            tempData[offset++] = deviceLower;
            //命令字
            if (cmd == Constant.DATA_START || cmd == Constant.DATA_END || cmd == Constant.DATA_TRANSFER_FLAG) {
                tempData[offset++] = Constant.DATA_TRANSFER_FLAG;
            }
            tempData[offset++] = cmd;
            //参数
            for (int x = 0; x < params.size(); x++) {
                if (params.get(x) == Constant.DATA_START || params.get(x) == Constant.DATA_END || params.get(x) == Constant.DATA_TRANSFER_FLAG) {
                    tempData[offset++] = Constant.DATA_TRANSFER_FLAG;
                }
                tempData[offset++] = params.get(x);
            }
            //数据和
            int dataSum = 0;
            for (int y = 1; y < offset; y++) {
                if (y < offset - 1 && tempData[y] == Constant.DATA_TRANSFER_FLAG && (tempData[y + 1] == Constant.DATA_TRANSFER_FLAG || tempData[y + 1] == Constant.DATA_START || tempData[y + 1] == Constant.DATA_END)) {
                    continue;
                }
                dataSum += tempData[y];
            }
            byte byteSum = (byte) dataSum;
            if (byteSum == Constant.DATA_START || byteSum == Constant.DATA_END || byteSum == Constant.DATA_TRANSFER_FLAG) {
                tempData[offset++] = Constant.DATA_TRANSFER_FLAG;
            }
            tempData[offset++] = byteSum;
            //协议结束位
            tempData[offset++] = Constant.DATA_END;
            byte[] finalTemp = new byte[offset];
            System.arraycopy(tempData, 0, finalTemp, 0, offset);
            sendDataToPort(cmd, mSerialPort, finalTemp, uploadStyle);
        } catch (Exception e) {
            addStrText("IOException:" + e.getMessage());
        }
    }

    /**
     * 通过串口发送数据
     *
     * @param cmd
     * @param serialPort
     * @param data
     */
    public void sendDataToPort(byte cmd, SerialPort serialPort, byte[] data, byte uploadStyle) {
        if (null == serialPort) {
            addStrText("-----必须先打开串口-----");
            return;
        }
        OutputStream out = null;
        try {
            out = serialPort.getOutputStream();
            out.write(data);
            out.flush();
            addStrText("0x" + Integer.toHexString(cmd) + (UPLOAD_ACTIVE == uploadStyle ?
                    "主动下发数据：" : "应答数据：") + Arrays.toString(data));
        } catch (IOException e) {
            addStrText("IOException:" + e.getMessage());
            e.printStackTrace();
        } finally {
            if (null != out) {
                try {
                    out.close();
                    out = null;
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }


    /**
     * 搜索端口
     *
     * @return
     */
    public ArrayList<String> findSerialPort() {
        Enumeration<CommPortIdentifier> portList = CommPortIdentifier.getPortIdentifiers();
        ArrayList<String> portNameList = new ArrayList<String>();
        StringBuffer stringBuffer = new StringBuffer();
        while (portList.hasMoreElements()) {
            String portName = portList.nextElement().getName();
            portNameList.add(portName);
            stringBuffer.append(portName + ",");
        }
        if (stringBuffer.length() > 0) {
            addStrText("可用端口：" + stringBuffer.substring(0, stringBuffer.length() - 1));
        }
        return portNameList;
    }

    /**
     * 打开指定端口
     *
     * @param portName 端口名称
     * @param baudrate 波特率
     * @return
     */
    public SerialPort openPort(String portName, int baudrate) {
        SerialPort serialPort = null;
        try {
            //通过端口名找到识别端口
            CommPortIdentifier commPortIdentifier = CommPortIdentifier.getPortIdentifier(portName);
            //打开端口，并给端口名字和timeout
            CommPort commPort = commPortIdentifier.open(this.getClass().getName(), 2000);
            //判断端口是不是串口
            if (commPort instanceof SerialPort) {
                addStrText(portName + "是串口");
                serialPort = (SerialPort) commPort;
                //设置串口参数(波特率，数据位=8位，停止位=1位，奇偶校验=无)
                serialPort.setSerialPortParams(baudrate, SerialPort.DATABITS_8,
                        SerialPort.STOPBITS_1, SerialPort.PARITY_NONE);
                serialPort.setFlowControlMode(SerialPort.FLOWCONTROL_NONE);
                addStrText(String.format(portName + "参数设置完成：波特率为%d,数据位为%d位,停止位为%d位," +
                                "无奇偶校验",
                        baudrate, SerialPort.DATABITS_8, SerialPort.STOPBITS_1));

            } else {
                addStrText(portName + "不是串口");
                commPort.close();
                commPort = null;
            }
        } catch (NoSuchPortException e) {
            addStrText(portName + "不存在");
            e.printStackTrace();
        } catch (PortInUseException e) {
            addStrText(portName + "被占用");
            e.printStackTrace();
        } catch (UnsupportedCommOperationException e) {
            addStrText("非法操作");
            e.printStackTrace();
        } catch (Exception e) {
            addStrText("Exception:" + e.getMessage());
            e.printStackTrace();
        }
        return serialPort;
    }

    private void addPortEventListener() {
        try {
            mSerialPort.addEventListener(new SerialListener());
            mSerialPort.notifyOnDataAvailable(true);
        } catch (Exception e) {
            e.printStackTrace();
            addStrText("too many listener added to serial port");
        }
    }


    /**
     * 关闭指定串口
     */
    public void closePort() {
        if (null != mSerialPort) {
            mSerialPort.removeEventListener();
            mSerialPort.close();
            addStrText(mSerialPort.getName() + "已关闭");
            mSerialPort = null;
        }
    }

    private byte[] tempData = {};

    /**
     * 串口监听器
     */
    private class SerialListener implements SerialPortEventListener {

        @Override
        public void serialEvent(SerialPortEvent serialPortEvent) {
            switch (serialPortEvent.getEventType()) {
                case SerialPortEvent.BI://通讯中断
                    addStrText("与串口设备通讯中断");
                    break;
                case SerialPortEvent.OE://溢位（溢出）错误
                    break;
                case SerialPortEvent.FE://帧错误
                    break;
                case SerialPortEvent.PE://奇偶校验错误
                    break;
                case SerialPortEvent.CD://载波检测
                    break;
                case SerialPortEvent.CTS://清除待发送数据
                    break;
                case SerialPortEvent.DSR://待发送数据准备好了
                    break;
                case SerialPortEvent.RI://振铃指示
                    break;
                case SerialPortEvent.OUTPUT_BUFFER_EMPTY://输出缓冲区已清空
                    break;
                case SerialPortEvent.DATA_AVAILABLE://串口存在可用数据
                    try {
                        Thread.sleep(Integer.parseInt(tf_delay_input.getText()));
                    } catch (Exception e) {

                    }
                    byte[] data = null;
                    if (null == mSerialPort) {
                        addStrText("串口对象为空");
                    } else {
                        data = readDataFromPort(mSerialPort);
                        if (null == data || data.length < 1) {
                            addStrText("未获取到有效数据");
                        } else {
                            interpretData(data);
                        }
                    }
                    break;
                default:
                    break;
            }
        }
    }

    private void interpretData(byte[] data) {
        try {
            addStrText("解析数据：" + Arrays.toString(data));
            if (null == data || data.length < 6) {
                addStrText("数据异常");
                return;
            }
            List<Byte> tempData = new ArrayList<Byte>();
            //和校验不包含开始位、结束位和和校验位
            //补位的0x10不包含在和校验和包长度中
            //和校验==除了开始位和结束位的数据和强转成byte
            for (int x = 1; x < data.length; x++) {
                if ((x < data.length - 2) && (data[x] == 0x10) && (data[x + 1] == 0x02 || data[x + 1] == 0x03 || data[x + 1] == 0x10)) {
                    x++;
                }
                tempData.add(data[x]);
            }
            //因为tempData中没有包含开始位，所以命令字下标为4
            byte[] deviceId = {tempData.get(2), tempData.get(3)};
            byte what = tempData.get(4);
            switch (what) {
                case Constant.CLOCK_SYNCHRONIZATION:
                    packageClockSynData(Constant.CLOCK_SYNCHRONIZATION, deviceId, UPLOAD_RESPONSE);
                    break;
                case Constant.DISPLAY_A:
                    packageDisplayData(Constant.DISPLAY_A, deviceId, UPLOAD_RESPONSE);
                    break;
                case Constant.DISPLAY_B:
                    packageDisplayData(Constant.DISPLAY_B, deviceId, UPLOAD_RESPONSE);
                    break;
                case Constant.UPDATE_PICTURE:
                    if (tf_pic_version.getText().length() == 0 || (((tempData.get(5) * 256 + tempData.get(6)) != Integer.parseInt(tf_pic_version.getText())) && tempData.get(9) == 0x03)) {
                        //如果发送过来的版本号与闸机版本号不一致，则应答
                        sendPicData(deviceId, UPLOAD_RESPONSE);
                    }
                    break;
                default:
                    addStrText("非法数据");
                    break;
            }
        } catch (Exception e) {
            addStrText("Exception:" + e.getMessage());
        }
    }


    /**
     * 从指定串口读取数据
     *
     * @param serialPort
     * @return
     */
    public byte[] readDataFromPort(SerialPort serialPort) {
        InputStream is = null;
        byte[] data = null;
        try {
            is = serialPort.getInputStream();
            int bufferlenth = is.available();
            while (bufferlenth != 0) {
                data = new byte[bufferlenth];
                is.read(data);
                bufferlenth = 0;
            }
        } catch (IOException e) {
            e.printStackTrace();
            addStrText("IOException:" + e.getMessage());
        } finally {
            if (is != null) {
                try {
                    is.close();
                    is = null;
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
//        addStrText("接收数据：" + Arrays.toString(data));
        return data;
    }


    public byte[] readFile(File file) {
        String encoding = "unicode";
        String laststr = "";
        BufferedReader reader = null;
        try {
            FileInputStream in = new FileInputStream(file);
            reader = new BufferedReader(new InputStreamReader(in, encoding));// 读取文件
            String tempString = null;
            while ((tempString = reader.readLine()) != null) {
                laststr = laststr + tempString;
            }
            reader.close();
        } catch (IOException e) {
            e.printStackTrace();
            addStrText("IOException:" + e.getMessage());
        } finally {
            if (reader != null) {
                try {
                    reader.close();
                } catch (IOException el) {
                    addStrText("IOException:" + el.getMessage());
                }
            }
        }
        byte[] tempData = null;
        try {
            byte[] origintempData = laststr.getBytes(encoding);
            tempData = new byte[origintempData.length - 2];
            System.arraycopy(origintempData, 2, tempData, 0, origintempData.length - 2);
        } catch (UnsupportedEncodingException e) {

        }
        return tempData;
    }

    private byte[] readFileByte(File file) {
        InputStream in = null;
        byte[] tempbytes = null;
        try {
            // 一次读多个字节
            int byteread = 0;
            in = new FileInputStream(file.getAbsolutePath());
            tempbytes = new byte[in.available()];
            // 读入多个字节到字节数组中，byteread为一次读入的字节数
            while ((byteread = in.read(tempbytes)) != -1) {
//                System.out.println(Arrays.toString(tempbytes));
            }
        } catch (Exception e1) {
            addStrText("Exception:" + e1.getMessage());
            e1.printStackTrace();
        } finally {
            if (in != null) {
                try {
                    in.close();
                } catch (IOException e1) {
                    addStrText("Exception:" + e1.getMessage());
                }
            }
        }
        return tempbytes;
    }


    private byte[] listTobyte(List<Byte> bytes) {
        if (null == bytes || 1 > bytes.size()) {
            return null;
        }
        byte[] data = new byte[bytes.size()];
        for (int x = 0; x < bytes.size(); x++) {
            data[x] = bytes.get(x);
        }
        return data;
    }

    private byte dataSum(List<Byte> temp) {
        int sum = 0;
        for (byte b : temp) {
            sum += b;
        }
        return (byte) sum;
    }

    private static byte charToByte(char c) {
        return (byte) "0123456789ABCDEF".indexOf(c);
    }

    @FXML
    private void onClearLogs(MouseEvent mouseEvent) {
        action_info.clear();
    }

    private void addStrText(final String str) {
        Platform.runLater(new Runnable() {
            @Override
            public void run() {
                action_info.appendText(str + "\n");
            }
        });

    }

}
